In today's digital age, an enormous amount of information, such as executable program code, documents, bank statements, insurance information, and the like, is stored as data on a variety of computing devices, such as servers, personal computers, tablet computing devices, and smart phones. The nature of such digitally-stored data renders it especially susceptible to unauthorized modification that is extremely difficult to detect with the naked eye. For example, an individual could change a few words in a few lines of a one hundred page contract to render that contract more favorable to that individual. In another example, an individual could insert a few lines of code into a program code including tens or hundreds of thousands or millions of fines of code. When that program code is executed, the additional fines of code cause one or more functions of the executed program to operate differently than intended. In one instance in which the program code is stored on and executable by an electronic gaming machine (EGM) to operate a wagering game, such as a video slot game, such unauthorized modifications could provide the individual with an advantage in the video slot game that no other player would receive. Such examples outline the necessity to authenticate certain data strings, such as confidential documents and program code, stored on a computing device to ensure that such data strings have not been modified in an unauthorized manner. For instance, prior to executing a program code stored on an EGM, the EGM authenticates the stored program code to determine whether it has been modified in an unauthorized manner.
While there are many ways to authenticate a data string, the use of a one-way hash function (referred to herein as a “hash function”) to determine whether a copy of a data string has been modified relative to the original data string (i.e., to authenticate the copy of the data string) is commonplace. Generally, a hash function is a function (such as a mathematical function) that converts a variable-length input string into a different, static-length output string commonly referred to as a result hash. Put differently, the input string is hashed using the hash function (i.e., input into the hash function) to obtain the result hash. Both the input string and the output string typically include letters, numbers, and/or other characters. For a given input string and a given hash function, when that input string is hashed using that hash function, the same result hash is always obtained. A hash function is referred to as a “one-way” hash function because it is relatively easy to use the hash function to obtain a result hash for a given input string (i.e., by hashing the input string using the hash function), but it is extremely difficult and, in certain instances, computationally infeasible, to obtain an input string for a given result hash. In other words, given an input string, it is easy to use the hash function to obtain the corresponding output string, but given an output string, it is nearly impossible to use the hash function to obtain the corresponding input string. Certain hash functions are collision resistant. For such a hash function, it is extremely difficult and, in certain instances, computationally infeasible, to determine two different input strings that, when hashed using the hash function (i.e., when input into the hash function), result in a same result hash. Thus, in such collision-resistant hash functions, each input string is associated with a unique corresponding result hash.
Since the same result hash is always obtained when a given input string is hashed using a given hash function, hash functions can be used to authenticate a copy of a data string by determining whether a result hash obtained from hashing the original data string is the same as a result hash obtained from hashing the copy of the data string. More specifically, a hash function is typically used to authenticate a copy of a data string in the following manner: (a) the original data string is hashed (such as at a first point in time) using a hash function to obtain a first result hash, (b) the copy of the data string is hashed (such as at a second subsequent point in time) using the same hash function to obtain a second result hash, and (c) the first result hash and the second result hash are compared to determine whether the first result hash and the second result hash are the same. If the first result hash and the second result hash are the same, the original data string and the copy of the data string are the same, and the copy of the data string is, therefore, authentic (i.e., has not been modified relative to the original data string). If the first result hash and the second result hash are different, the data string and the copy of the data string are not the same, and the copy of the data string is, therefore, not authentic (i.e., has been modified relative to the original data string).
In one example, Joe creates a document that Joe intends to email to Eileen. Before emailing a copy of the document to Eileen, Joe instructs his computer to hash the document (which is the input string in this example) using a hash function to obtain a first result hash. Joe emails a copy of the document and the first result hash to Eileen. After receiving the copy of the document and the first result hash, Eileen instructs her computer to hash the copy of the document using the same hash function to obtain a second result hash. Eileen compares the first result hash with the second result hash. If the two result hashes are the same, Eileen knows that the copy of the document is the same as the document Joe created. If the two result hashes are different, Eileen knows that the copy of the document is not the same as the document Joe created.
In another example, Dan creates a document and saves the document on the hard drive of his computer. Dan is going on vacation, and wants to be sure that the document is not altered by his roommate Joey while he is away. Dan instructs his computer to hash the document (which is the input string in this example) using a hash function to obtain a first result hash, and stores the first result hash in a secure location. After returning from vacation, Dan again instructs his computer to hash the document using the same hash function to obtain a second result hash. Dan compares the first result hash with the second result hash. If the two result hashes are the same, Dan knows that the document was not altered since he first hashed the document. If the two result hashes are different, Dan knows that the document was altered since he first hashed the document.
In most instances, a data string is too large to be hashed at once. In such instances, the data string is typically divided into a plurality of data string pieces arranged in a designated order, and those data string pieces are sequentially hashed in the designated order. In these instances, a first data string piece in the designated order and a default seed are hashed using a hash function (i.e., are input into the hash function) to obtain a first result hash. For each subsequent data string piece in the designated order: (a) that data string piece, and (b) the result hash obtained from hashing the data string piece immediately preceding that data string piece in the designated order are hashed using the hash function (i.e., are input into the hash function) to obtain a result hash. Thus, it should be appreciated that in these instances the Nth data string piece cannot be hashed until the N−1th data string piece has been hashed because the result hash obtained from hashing the N−1th data string piece is used as one of the inputs to the hash function when the Nth data string piece is hashed. When each data string piece has been hashed, the final result hash represents the result of the entire data string being hashed.
The quantity of data string pieces into which the data string is divided is typically determined based on the hash function used to hash the data string. That is, certain hash functions only operate on data string pieces of a specific size. For example, an MD5 hash hashes 128 bit data string pieces. Thus, in this example, the data string is divided into a plurality of 128 bit data string pieces, and then those pieces are hashed using the MD5 hash in the manner described above. Specifically, in this example, the quantity of data string pieces is equal to the size of the data string, in bytes, divided by sixteen and rounded up.
FIG. 1 is a block diagram illustrating an example hash of a program code (i.e., a data string) too large to be hashed at once. In this example, the program code is divided into the following four pieces to be hashed using a hash function 105 in the following designated order: a first piece of the program code 120, a second piece of the program code 220, a third piece of the program code 320, and a fourth piece of the program code 420. First piece of the program code 120 and a default seed 110 are first hashed using hash function 105 to obtain a first result hash 130. That is, first piece of the program code 120 and default seed 110 are input into hash function 105, and first result hash 130 is obtained as the output of hash function 105. Next, second piece of the program code 220 and first result hash 130 (i.e., the result hash obtained from hashing the piece of the program code immediately preceding second piece of the program code 220 in the designated order) are hashed using hash function 105 to obtain a second result hash 230. That is, second piece of the program code 220 and first result hash 130 are input into hash function 105, and second result hash 230 is obtained as the output of hash function 105.
Next, third piece of the program code 320 and second result hash 230 (i.e., the result hash obtained from hashing the piece of the program code immediately preceding third piece of the program code 320 in the designated order) are hashed using hash function 105 to obtain a third result hash 330. That is, third piece of the program code 320 and second result hash 230 are input into hash function 105, and third result hash 330 is obtained as an output of hash function 105. Next, fourth piece of the program code 420 and third result hash 330 (i.e., the result hash obtained from hashing the piece of the program code immediately preceding fourth piece of the program code 420 in the designated order) are hashed using hash function 105 to obtain a final result hash 430. That is, fourth piece of the program code 420 and third result hash 330 are input into hash function 105, and fourth result hash 430 is obtained as an output of hash function 105. Since fourth piece of the program code 420 is the piece of the program code that follows all other pieces of the program code in the designated order, the result hash obtained from hashing fourth piece of the program code 420 is the final result hash. It should be appreciated from the above example that this process of hashing a plurality of pieces of a data string (a plurality of pieces of a program code in the above example) is inherently sequential.
Hash functions are commonly used to authenticate a copy of a program code stored on a computing device before executing the copy of the program code. Put differently, hash functions are commonly used to ensure that a copy of a program code to be executed by a computing device is the same as the original program code. For example, a program code representing a video poker game to be operated by an EGM is created by a group of programmers at a first point in time. Before a copy of the program code is stored on the EGM, the program code is hashed using a hash function to obtain a result hash called an authentication final result hash. The authentication final result hash is encrypted and stored in association with a copy of the program code on the EGM. For instance, the copy of the program code and the encrypted authentication final result hash are sent to the EGM by a server through a data network and are stored on a memory device of the EGM. When the EGM receives an instruction to execute the copy of the program code, such as upon EGM startup, the EGM authenticates the copy of the program code before executing the copy of the program code. Specifically, the EGM authenticates the copy of the program code by: (a) hashing the copy of the program code stored on the EGM using the hash function (i.e., the same hash function used to obtain the authentication final result hash) to obtain a final result hash; (b) decrypting the authentication final result hash stored in association with the copy of the program code; and (c) comparing the authentication final result hash with the final result hash. If the authentication final result hash and the final result hash are the same, the EGM determines that the copy of the program code stored on the EGM is authentic (i.e., is the same as the program code hashed to obtain the authentication final result hash) and executes the copy of the program code. If the authentication final result hash and the final result hash are not the same, the EGM determines that the copy of the program code stored on the EGM is not authentic (i.e., is not the same as the program code hashed to obtain the authentication final result hash) and does not execute the copy of the program code.
As described above, in most cases a data string to be hashed is too large to hash at once, so the data string is divided into pieces and sequentially hashed in a designated order to obtain a final result hash. The final result hash is, in turn, compared to an authentication final result hash to authenticate the data string. More specifically, for each data string piece following the first data string piece (if any) in the designated order, that data string piece is hashed with the result hash obtained from hashing the immediately preceding data sting piece in the designated order to obtain a result hash, which is subsequently used as an input to the hash of the subsequent data string piece in the designated order. That is, for each data string piece following the first data string piece in the designated order, that data string piece cannot be hashed until the immediately preceding data string piece in the designated order has been hashed.
As the size of the data string to be authenticated using the hash function increases, the quantity of data string pieces that must be individually hashed increases. Since such hashing must be performed sequentially on each data string piece, as the size of the data string increases the time it takes to hash the data string pieces also increases. For example, it takes a typical EGM up to 30 seconds to hash and authenticate a single program code in such a manner. It also takes this typical EGM additional time to hash and authenticate other data, such as paytable data, sound data, image data, textual data, and video data. On EGMs including multiple program codes (e.g., EGMs configured to operate multiple games), this amount of time is increased by a multiple that is equal to the quantity of program codes. For example, an EGM including ten program codes to be authenticated takes over 300 seconds to hash and authenticate the program codes.
This relatively long authentication period increases the time it takes the EGM to initialize and, therefore, directly decreases the amount of time the EGM is available to be played by players and directly increases the amount of time casino (or other gaming establishment) personnel must supervise the EGM initialization process to ensure there are no problems. Further, since such authentication only determines whether a single final result hash is the same as a single authentication final result hash, there is no way for casino personnel to pinpoint where an unauthorized modification lies when authentication fails. There is, therefore, a continuing need to provide systems and methods that speed the authentication process by simultaneously hashing multiple pieces of a data string using a hash function, and to provide systems and methods that enable unauthorized modifications in data strings to be pinpointed.